﻿using System;
using System.IO;
//using System.Linq;
using System.Text;
using System.Xml;
using repliback4.Net.Identification;
using repliback4.Net.Protocol;
using repliback4.XmlStreaming;
using Tools.Debugging;
using System.Collections.Generic;
using repliback4.Net.Protocol.SASLMechanisms;
using System.Threading;
using Tools.SubStream;
using Tools;
using Tools.File.Hashing;
using System.Configuration;
using repliback4.Misc;


namespace testapp {


    class Program {

        static void Main ( string[] args ) {
            Thread.CurrentThread.Name = "main";
            Console.OutputEncoding = Encoding.UTF8;
            Console.WindowWidth = 160;
            testServer( );
            //testClient( );
            //testParser( );
            //testWriter( );
            //testXml( );
            //testSSL( );
            //testPlain( );
            //testQueue( );
            //testStream( );
            //testHasher( );


            //tesctClientServer( );
            Console.WriteLine( "any key to quit" );
            Console.ReadKey( );
            //XmlReaole.ReadKey( );

        }
        protected static ManualResetEvent serverStarted = new ManualResetEvent( false );
        private static void testClient ( ) {

            Logger.Debug( typeof( Program ), "server started, running client" );
            repliback4.Net.ClientSide.Client client = new repliback4.Net.ClientSide.Client( );
            client.Connect( "repliback.net", 5566 );
        }

        private static void testClientServer ( ) {
            //Thread tServer = new Thread( new ThreadStart( testServer ) );
            Thread tClient = new Thread( new ThreadStart( testClient ) );
            //tServer.Start( );
            tClient.Start( );
        }

        private static void testHasher ( ) {
            FileHasher fh = new FileHasher( "testdata.dat" );
            HashingSettings hs = new HashingSettings( );
            hs.BlockLength = 1024 * 256;

            DateTime start = DateTime.Now;
            fh.Hash( hs );
            DateTime end = DateTime.Now;

            fh.FragmentList.Sort( new Comparison<HashFragment>(
                ( a, b ) => ( int ) ( a.Range.From - b.Range.From )
            ) );
            StreamWriter twrt = File.CreateText( "testdata.md5" );
            foreach ( HashFragment hFragment in fh.FragmentList ) {
                twrt.WriteLine( "{1} *{0}", hFragment.Range, hFragment.Data, hFragment.Stream.Length );
            }
            twrt.Flush( );

            Console.WriteLine( "time: {0}", end - start );

        }

        public static ManualResetEvent hold = new ManualResetEvent( false );

        struct WorkerData {
            public String Name;
            public MuxerSubStream Stream;
        }

        protected static void worker ( Object data ) {
            WorkerData wData = ( WorkerData ) data;
            Console.WriteLine( "Stream {0} waiting", wData.Name );
            String fout = String.Format( "outdata.{0}.dat", wData.Name );
            Console.WriteLine( "Stream {0} will rewrite to {1} {2} bytes", wData.Name, fout, wData.Stream.Length );

            hold.WaitOne( );

            BinaryReader srdr = new BinaryReader( wData.Stream );
            Stream wstream = File.OpenWrite( fout );

            BinaryWriter swrt = new BinaryWriter( wstream );


            Console.WriteLine( "Stream {0} starting", wData.Name );

            byte[] buf = srdr.ReadBytes( ( int ) wData.Stream.Length );

            swrt.Write( buf );
            Console.WriteLine( "Stream {0} done", wData.Name );

        }

        protected static void testStream ( ) {
            StreamMuxer strMux = new StreamMuxer( File.OpenRead( "testdata.dat" ) );
            int length = 1024 * 1024;
            int i = -1;
            do {
                i++;
                MuxerSubStream sub = strMux.AddSubStream( new Range( i * length, length ), "sub" + i );
                Thread t = new Thread( new ParameterizedThreadStart( worker ) );
                t.Start( new WorkerData( ) { Name = "sub" + i, Stream = sub } );
            } while ( i * length + length < strMux.InnerStream.Length );

            Console.WriteLine( "pres key to start" );
            Console.ReadKey( );
            hold.Set( );

        }
        #region tests
        private static void testQueue ( ) {
            QueueTest qt = new QueueTest( );
        }

        private static void testPlain ( ) {




        }

        //private static void testSSL ( ) {
        //    FileStream fs = new FileStream( "d://data.txt", FileMode.Create, FileAccess.ReadWrite );
        //    FileStream dbgfs = new FileStream( "d://dbgdata.txt", FileMode.Create, FileAccess.ReadWrite );
        //    StreamMultiplexer mx = new StreamMultiplexer( fs );
        //    mx.AddStream( dbgfs );
        //    //XmlWriter xw = XmlWriter.Create( mx );
        //    XmlDocument xdoc = new XmlDocument( );
        //    xdoc.AppendChild( xdoc.CreateXmlDeclaration( "1.0", "UTF-8", "yes" ) );
        //    XmlElement root = xdoc.AppendChild( xdoc.CreateElement( "root" ) ) as XmlElement;
        //    XmlElement child = root.AppendChild( xdoc.CreateElement( "child" ) ) as XmlElement;
        //    root.SetAttribute( "piesek", "kotek" );
        //    child.SetAttribute( "attr", "krowka" );
        //    xdoc.Save( mx );
        //    //System.Net.Security.SslStream ssStream = new System.Net.Security.SslStream( fs, true );
        //ssStream.AuthenticateAsClient( "pies.net" );

        // }

        private static void testXml ( ) {
            //XmlDocument xDoc = new XmlDocument( );

            //XmlNode root = xDoc.AppendChild( xDoc.CreateElement( "root", "my-ns" ) );
            //( ( XmlElement ) root ).SetAttributeNode( xDoc.CreateAttribute( "xmlns", "xxx", xDoc.GetNamespaceOfPrefix( "xmlns" ) ) ).Value = "dead-ns";
            //XmlNode el = root.AppendChild( xDoc.CreateElement( "el", "other-ns" ) );
            //XmlNode subel = el.AppendChild( xDoc.CreateElement( "subel","dead-ns") );
            //Console.WriteLine( subel.NamespaceURI );

            XmlWriterSettings xws = new XmlWriterSettings( );
            xws.ConformanceLevel = ConformanceLevel.Fragment;
            XmlWriter xw = XmlWriter.Create( Console.Out, xws );

            //xDoc.WriteTo( xw );

            xw.WriteStartElement( "pies" );
            xw.WriteStartAttribute( "attr" );
            xw.WriteEndAttribute( );
            xw.WriteWhitespace( "" );
            xw.Flush( );
        }

        private static void testWriter ( ) {
            XmlStreamWriter xswrt = new XmlStreamWriter( Console.Out );
            xswrt.OpenDocument( );

            repliback4.Net.Protocol.Messages.Stream stream = new repliback4.Net.Protocol.Messages.Stream( xswrt.Document );
            stream.From = Rid.Parse( "piesek@buda.pl:345/taki/se/resource" );
            stream.To = Rid.Parse( "kuweta.pl" );

            xswrt.OpenStream( stream );

            repliback4.Net.Protocol.Messages.StreamFeatures sFeatures = new repliback4.Net.Protocol.Messages.StreamFeatures( xswrt.Document );



            repliback4.Net.Protocol.Messages.SASLMechanisms mechanisms = new repliback4.Net.Protocol.Messages.SASLMechanisms( xswrt.Document );

            //iQuery.Type = repliback4.Net.Protocol.Messages.Iq.IqTypes.Get;
            sFeatures.AddFeature( mechanisms );
            xswrt.WriteStanza( sFeatures );

            xswrt.CloseStream( );//stream

            xswrt.Flush( );
            Console.WriteLine( "\n\n\ndone" );
        }

        private static void testParser ( ) {
            //String testString = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><stream:stream from=\"gmail.com\" id=\"E6E133531D67CF92\" version=\"1.0\" xmlns:stream=\"http://etherx.jabber.org/streams\" xmlns=\"jabber:client\"><stream:features><mechanisms xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\"><mechanism>PLAIN</mechanism><mechanism>X-GOOGLE-TOKEN</mechanism></mechanisms></stream:features>";
            String testA = File.ReadAllText( "testA.xml", Encoding.UTF8 );
            String testB = File.ReadAllText( "testB.xml", Encoding.UTF8 );
            MessageParser mParser = new MessageParser( );
            mParser.OnStreamBegin += new MessageParser.OnStreamBeginHandler( mParser_OnStreamBegin );
            mParser.OnStreamEnd += new MessageParser.OnStreamEndHandler( mParser_OnStreamEnd );
            mParser.OnTag += new MessageParser.OnTagHandler( mParser_OnTag );
            mParser.OnStreamError += new MessageParser.OnStreamErrorHandler( mParser_OnStreamError );
            mParser.OnXmlDeclaration += new MessageParser.OnXmlDeclarationHandler( mParser_OnXmlDeclaration );
            mParser.Parse( testA );
            mParser.Parse( testB );
        }

        #region mParser events
        static void mParser_OnXmlDeclaration ( object xmlDeclaration ) {
            Logger.Debug( typeof( Program ), "xmlDeclaration" );
        }

        static void mParser_OnStreamError ( ) {
            Logger.Debug( typeof( Program ), "stream error" );
        }

        static void mParser_OnTag ( repliback4.Net.Protocol.Messages.ReplibackTag stanza ) {
            Logger.Debug( typeof( Program ), String.Format( "tag\t{0}", stanza.GetType( ).FullName ) );
        }

        static void mParser_OnStreamEnd ( repliback4.Net.Protocol.Messages.ReplibackTag stream ) {
            Logger.Debug( typeof( Program ), String.Format( "streamEnd" ) );
        }

        static void mParser_OnStreamBegin ( repliback4.Net.Protocol.Messages.ReplibackTag stream ) {
            Logger.Debug( typeof( Program ), String.Format( "streamBegin {0}", stream.GetType( ).FullName ) );
        }
        #endregion
        #endregion
        static void testServer ( ) {
            repliback4.Net.ServerSide.ServerSettings settings = new repliback4.Net.ServerSide.ServerSettings( new ConfigFile( "cfg.xml", "server" ) );
            repliback4.Net.ServerSide.Server server = new repliback4.Net.ServerSide.Server( settings );
            server.Start( );
            serverStarted.Set( );
        }
    }
}
